

// SDF 绘制圆
// float map( vec3 p ){
//     // 圆心在原点 半径为1的圆
//     return length(p) - 1.0;
// }

// 3D 圆角矩形的 SDF
float sdRoundedBox(vec3 p, vec3 size, float radius) {
    vec3 q = abs(p) - (size - vec3(radius));
    return min(max(q.x, max(q.y, q.z)), 0.0) + length(max(q, 0.0)) - radius;
}
// 修改后的 SDF 函数
float map(vec3 p) {
    // 定义圆角矩形的大小和圆角半径
    vec3 size = vec3(2.0, 1.0, 1.0); // 圆角矩形在x、y、z三个轴上的大小
    float radius = 0.5; // 圆角半径
    return sdRoundedBox(p, size, radius);
}

/*
    ro: 射线起点
    rd: 射线方向

    整个函数的逻辑就是 不断让光线长度增加 使用 map 计算当前光线终点与物体表面的距离d0 
    判断d0是否小于0.001 或者 d是否大于40.0 如果是则停止循环
    然后下一次循环将d0与光线方向相乘 让光线(终点)不断前进 
    再计算终点与物体表面的距离 这个距离再进行判断 如此循环
*/
float RayMarch( vec3 ro, vec3 rd ){
    float d = 0.0;
    for ( int i = 0; i < 255; i++ ) {
        // 当前光线终点由 光的起点 + 光的方向 * 终点与物体表面的距离(初始值为0)
        vec3 p = ro + rd * d;
        // 使用SDF计算 光的终点与物体表面的距离 小于0.001 包括负数
        float  d0 = map(p);
        // 当前光线终点距离圆表面小于0.001 表示光线照射到了模型表面
        // 或者 距离大于40.0 停止循环 
        if ( d0 <= 0.001 || d >= 40.0 ) break;
        d+=d0;
    }
    return d;
}

vec3 GetNormal( vec3 p ) {
    float d = map(p);
    // e 是微小偏移量 
    // 求偏导数但是没有分母的原因是 最后三个分量都要做归一化 所以分母可以约掉
    vec2 e = vec2( 0.001, 0.0 );
    // e.xyy 就是在x轴上的分量 + 一个微小偏移量 e.yxy e.yyx同理
    float dx = d - map( p - e.xyy );
    float dy = d - map( p - e.yxy );
    float dz = d - map( p - e.yyx );
    return normalize( vec3( dx, dy, dz ) );
}


void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    // 原点移动到屏幕中心
    uv -= 0.5;
    // 调整纵横比 在窗口变化时图像比例不变
    uv.x *= iResolution.x / iResolution.y;
    vec3 colorOutput = vec3(0.0);

    // ro是射线的起点( 注意区分光源起点和射线起点 射线起点是人眼/摄像机的位置 后面才设置光源位置 )
    vec3 ro = vec3(0.0, 0.0, -13.0);
    // 当前像素点坐标作为方向, 相当于人眼之前摆的屏幕上的像素 射线方向: 从 点ro -> 点vec(uv, 1.0), 
    vec3 rd = normalize(vec3(uv, 1.0)); 
    
    float d = RayMarch(ro, rd); 

    // 小于40的光线长度说明已经到达了物体表面[ 看RayMarch()函数的终止条件, 大于40的光线都会被忽略, 所以此处使用40.0 ]
    if ( d < 40.0 ) {
        vec3 p = ro + rd * d;
        // Phong 光照模型
        vec3 n = GetNormal(p);
        // 自定义光源
        vec3 lightPos = vec3( 3.0, 5.0, -5.0 );
        // 光源与物体表面射线落点的方向向量
        vec3 lightDir = normalize( lightPos - p );
        // 漫反射光照
        float diffuse = dot( n , lightDir );
        // 使用半兰伯特光照模型 0.5是为了让漫反射光照更加柔和 +0.5为了全局更亮
        diffuse = diffuse * 0.5 + 0.5;
        vec3 lightcolor = vec3(0.2,0.7,1.0);
        lightcolor *= diffuse;
        colorOutput += lightcolor;
    }

    gl_FragColor = vec4( colorOutput, 1.0 );
}